Dictionaries

A key -> value store


In [78]:
## List access
fruit = ['cranberries', 'apples']

print(fruit[0])


cranberries

In [91]:
## As storage
string_key_to_int_value = {'one': 1, 'two': 2}

print(string_key_to_int_value)

int_key_to_string_value = {1: 'one', 2: 'two'}

print(int_key_to_string_value)

fruit = {
    'apples': 10,
    'oranges': 25,
    'pears': 15
}

print(fruit)

## Bought more apples
print('Has walnuts? ', fruit.get('walnut'))
fruit['apples'] += 10

print(fruit)
print('Has walnuts? ', fruit.get('walnut', 0))


{'one': 1, 'two': 2}
{1: 'one', 2: 'two'}
{'apples': 10, 'oranges': 25, 'pears': 15}
Has walnuts?  None
{'apples': 20, 'oranges': 25, 'pears': 15}
Has walnuts?  0

Combining two or more dictionaries dictionaries


In [102]:
from pprint import pprint

basement_rooms = {'den': 300, 'living_room': 500}
ground_level_rooms = {'kitchen': 250, 'guest_bed_room_one': 300}
upstairs_rooms = {'master_bed_room': 400, 'guest_bath': 150}

upper_floors = upstairs_rooms.copy()
upper_floors.update(ground_level_rooms)

print('Upper level rooms have')
pprint(upper_floors)
print()

entire_house = upper_floors.copy()
entire_house.update(basement_rooms)

print('All rooms in house')
pprint(entire_house)

print()
for room, square_feet in entire_house.items():
    print(room, ':', square_feet)
    print()


Upper level rooms have
{'guest_bath': 150,
 'guest_bed_room_one': 300,
 'kitchen': 250,
 'master_bed_room': 400}

All rooms in house
{'den': 300,
 'guest_bath': 150,
 'guest_bed_room_one': 300,
 'kitchen': 250,
 'living_room': 500,
 'master_bed_room': 400}

guest_bed_room_one : 300

den : 300

kitchen : 250

living_room : 500

master_bed_room : 400

guest_bath : 150

Combining two or more dictionaries dictionaries


In [104]:
from pprint import pprint

basement_rooms = {'den': 300, 'living_room': 500}
ground_level_rooms = {'kitchen': 250, 'guest_bed_room_one': 300}
upstairs_rooms = {'master_bed_room': 400, 'guest_bath': 150}

upper_floors = upstairs_rooms.copy()
upper_floors.update(ground_level_rooms)

## Note no change if I go and add a room to the ground_level_rooms after creating upper_floors
ground_level_rooms['bathroom'] = 200

print('Ground level rooms')
pprint(ground_level_rooms)
print()

print('Upper level rooms have')
pprint(upper_floors)


Ground level rooms
{'bathroom': 200, 'guest_bed_room_one': 300, 'kitchen': 250}

Upper level rooms have
{'guest_bath': 150,
 'guest_bed_room_one': 300,
 'kitchen': 250,
 'master_bed_room': 400}

In [127]:
big_rooms = {'living': 500, 'kitchen': 700}
small_rooms = {'living': 200}

my_rooms = big_rooms.copy()

print(my_rooms)

my_rooms.update(small_rooms)

print(my_rooms)


{'kitchen': 700, 'living': 500}
{'kitchen': 700, 'living': 200}

Mutations are possible

Much like the lists, a dictionary can end up changing other dictionaries even with a copy.

Why care about Deep vs Shallow Copies

The performance and memory taken up on a machine. In general the idea is shown below.

A deep copy takes up double the amount of space, but prevents accidental data overrides.

A = [1, 2, 3, 4, 5]


B = [1, 2, 3, 4, 5]

A shallow copy takes up a marginal amount of extra space but allows for changing of data.

A = [1, 2, 3, 4, 5]

B => A
Number Fruits in a list -- mutated list version

In [109]:
from pprint import pprint

number_of_fruits = {
    'apples': 10,
    'pears': 15,
    'plums': 4
}

number_of_vegetables = {
    'carrots': 10,
    'celery': 3,
    'sprouts': 15
}

food_amounts = [number_of_fruits, number_of_vegetables]

pprint(food_amounts)

## If I change the number_of_fruits it updates the values inside of food_amounts
number_of_fruits['apples'] = 20

print()
pprint(food_amounts)


[{'apples': 10, 'pears': 15, 'plums': 4},
 {'carrots': 10, 'celery': 3, 'sprouts': 15}]

[{'apples': 20, 'pears': 15, 'plums': 4},
 {'carrots': 10, 'celery': 3, 'sprouts': 15}]
Number Fruits in a dictionary -- setting up the data, base case

In [111]:
from pprint import pprint

number_of_fruits = {
    'apples': 10,
    'pears': 15,
    'plums': 4
}

number_of_vegetables = {
    'carrots': 10,
    'celery': 3,
    'sprouts': 15
}

food_box_one = {
    'fruit': number_of_fruits.copy(), # Do a copy so updating the number of fruits does not break them
    'vegetables': number_of_vegetables.copy()
}

food_box_two = food_box_one.copy()

number_of_fruits['apples'] = 100000

# Currently the values are the same and 'apples' is not updated
pprint(food_box_one)
print()
pprint(food_box_two)


{'fruit': {'apples': 10, 'pears': 15, 'plums': 4},
 'vegetables': {'carrots': 10, 'celery': 3, 'sprouts': 15}}

{'fruit': {'apples': 10, 'pears': 15, 'plums': 4},
 'vegetables': {'carrots': 10, 'celery': 3, 'sprouts': 15}}
Number Fruits in a dictionary -- Shallow Copy

In [115]:
from pprint import pprint

number_of_fruits = {
    'apples': 10,
    'pears': 15,
    'plums': 4
}

number_of_vegetables = {
    'carrots': 10,
    'celery': 3,
    'sprouts': 15
}

food_box_one = {
    'fruit': number_of_fruits.copy(),
    'vegetables': number_of_vegetables.copy()
}

food_box_two = food_box_one.copy()

# Updating the fruits inside the food_box_one updates it inside of food_box_two
food_box_one['fruit']['apples'] = 25

print('Food box one')
pprint(food_box_one)
print()
print('Food box two')
pprint(food_box_two)


Food box one
{'fruit': {'apples': 25, 'pears': 15, 'plums': 4},
 'vegetables': {'carrots': 10, 'celery': 3, 'sprouts': 15}}

Food box two
{'fruit': {'apples': 25, 'pears': 15, 'plums': 4},
 'vegetables': {'carrots': 10, 'celery': 3, 'sprouts': 15}}
Number Fruits in a dictionary -- Deep Copy

In [117]:
from copy import deepcopy
from pprint import pprint

number_of_fruits = {
    'apples': 10,
    'pears': 15,
    'plums': 4
}

number_of_vegetables = {
    'carrots': 10,
    'celery': 3,
    'sprouts': 15
}

food_box_one = {
    'fruit': number_of_fruits.copy(),
    'vegetables': number_of_vegetables.copy()
}

food_box_two = deepcopy(food_box_one)

# Updating the fruits inside the food_box_one updates it inside of food_box_two
food_box_one['fruit']['apples'] = 25

print('Food box one')
pprint(food_box_one)

print()
print('Food box two')
pprint(food_box_two)


Food box one
{'fruit': {'apples': 25, 'pears': 15, 'plums': 4},
 'vegetables': {'carrots': 10, 'celery': 3, 'sprouts': 15}}

Food box two
{'fruit': {'apples': 10, 'pears': 15, 'plums': 4},
 'vegetables': {'carrots': 10, 'celery': 3, 'sprouts': 15}}

Example with Chores, People, Rooms, and cleaning

This example will use lists and dictionaries to setup who chould do which chores in a home.

Key Concepts

  • Lists
  • Dictionaries
  • Iteration
  • Nested loop avoidance strategies via dictionaires

Room setup


In [118]:
from pprint import pprint

chores = ['sweeping', 'vacuuming', 'dusting', 'windows']
people = ['kid_one', 'kid_two', 'adult_one', 'adult_two']
rooms = [
    'kitchen', 'living_room', 'dining_room', 'bedroom_one',
    'bedroom_two', 'master_bedroom', 'bedroom_three', 'basement',
    'attic'
]

rooms_with_size = {
    'kitchen': 400,
    'living_room': 200,
    'dining_room': 250,
    'bedroom_one': 400,
    'bedroom_two': 300,
    'master_bedroom': 350,
    'bedroom_three': 200,
    'basement': 800,
    'attic': 475
}

# Assign the chores to each room
rooms_with_chores = {}
for room in rooms:
    rooms_with_chores[room] = chores.copy()
    
pprint(rooms_with_chores)


{'attic': ['sweeping', 'vacuuming', 'dusting', 'windows'],
 'basement': ['sweeping', 'vacuuming', 'dusting', 'windows'],
 'bedroom_one': ['sweeping', 'vacuuming', 'dusting', 'windows'],
 'bedroom_three': ['sweeping', 'vacuuming', 'dusting', 'windows'],
 'bedroom_two': ['sweeping', 'vacuuming', 'dusting', 'windows'],
 'dining_room': ['sweeping', 'vacuuming', 'dusting', 'windows'],
 'kitchen': ['sweeping', 'vacuuming', 'dusting', 'windows'],
 'living_room': ['sweeping', 'vacuuming', 'dusting', 'windows'],
 'master_bedroom': ['sweeping', 'vacuuming', 'dusting', 'windows']}

Room and chore setup


In [120]:
from pprint import pprint
from random import choice

chores = ['sweeping', 'vacuuming', 'dusting', 'windows']
people = ['kid_one', 'kid_two', 'adult_one', 'adult_two']
rooms = [
    'kitchen', 'living_room', 'dining_room', 'bedroom_one',
    'bedroom_two', 'master_bedroom', 'bedroom_three', 'basement',
    'attic'
]

rooms_with_size = {
    'kitchen': 400,
    'living_room': 200,
    'dining_room': 250,
    'bedroom_one': 400,
    'bedroom_two': 300,
    'master_bedroom': 350,
    'bedroom_three': 200,
    'basement': 800,
    'attic': 475
}

# Assign the chores to each room
rooms_with_chores = {}
for room in rooms:
    rooms_with_chores[room] = chores.copy()
    

# Assign rooms to people
people_with_rooms = {}
rooms_to_clean = rooms.copy()

while len(rooms_to_clean) > 0:
    
    # Randomly assign a person to a chore
    person = choice(people) 
    room = choice(rooms_to_clean)
    
    # Need to make sure we only add rooms to the list of rooms
    # if the person has already been given at least one room
    if person in people_with_rooms:
        people_with_rooms[person].append(room)
    else:
        people_with_rooms[person] = [room]
    
    # This ensures we stop our loop at some point
    rooms_to_clean.remove(room)

# Ensure everyone has something to clean, even if it's no rooms at all
for person in people:
    if person not in people_with_rooms:
        people_with_rooms[person] = []

# Show which rooms are assigned to which people
pprint(people_with_rooms)


{'adult_one': [],
 'adult_two': ['attic', 'bedroom_two', 'kitchen'],
 'kid_one': ['bedroom_one', 'dining_room', 'bedroom_three'],
 'kid_two': ['master_bedroom', 'living_room', 'basement']}

Figure out how much each person cleans -- takes more CPU time


In [123]:
from pprint import pprint
from random import choice

chores = ['sweeping', 'vacuuming', 'dusting', 'windows']
people = ['kid_one', 'kid_two', 'adult_one', 'adult_two']
rooms = [
    'kitchen', 'living_room', 'dining_room', 'bedroom_one',
    'bedroom_two', 'master_bedroom', 'bedroom_three', 'basement',
    'attic'
]

rooms_with_size = {
    'kitchen': 400,
    'living_room': 200,
    'dining_room': 250,
    'bedroom_one': 400,
    'bedroom_two': 300,
    'master_bedroom': 350,
    'bedroom_three': 200,
    'basement': 800,
    'attic': 475
}

# Assign the chores to each room
rooms_with_chores = {}
for room in rooms:
    rooms_with_chores[room] = chores.copy()
    

# Assign rooms to people
people_with_rooms = {}
rooms_to_clean = rooms.copy()

while len(rooms_to_clean) > 0:
    
    # Randomly assign a person to a chore
    person = choice(people) 
    room = choice(rooms_to_clean)
    
    # Need to make sure we only add rooms to the list of rooms
    # if the person has already been given at least one room
    if person in people_with_rooms:
        people_with_rooms[person].append(room)
    else:
        people_with_rooms[person] = [room]
    
    # This ensures we stop our loop at some point
    rooms_to_clean.remove(room)

# Ensure everyone has something to clean, even if it's no rooms at all
for person in people:
    if person not in people_with_rooms:
        people_with_rooms[person] = []


# Less efficient way to 
amount_cleaned_by_person = {}
for person, rooms in people_with_rooms.items():
    
    amount_cleaned_by_person[person] = 0
    
    for room in rooms:
        amount_cleaned_by_person[person] += rooms_with_size[room]

pprint(amount_cleaned_by_person)


{'adult_one': 1200, 'adult_two': 1075, 'kid_one': 0, 'kid_two': 1100}

Figure out how much each person cleans -- takes less CPU time


In [124]:
from pprint import pprint
from random import choice

chores = ['sweeping', 'vacuuming', 'dusting', 'windows']
people = ['kid_one', 'kid_two', 'adult_one', 'adult_two']
rooms = [
    'kitchen', 'living_room', 'dining_room', 'bedroom_one',
    'bedroom_two', 'master_bedroom', 'bedroom_three', 'basement',
    'attic'
]

rooms_with_size = {
    'kitchen': 400,
    'living_room': 200,
    'dining_room': 250,
    'bedroom_one': 400,
    'bedroom_two': 300,
    'master_bedroom': 350,
    'bedroom_three': 200,
    'basement': 800,
    'attic': 475
}

# Assign the chores to each room
rooms_with_chores = {}
for room in rooms:
    rooms_with_chores[room] = chores.copy()
    

# Assign rooms to people AND how much they will clean
people_with_rooms = {}
rooms_to_clean = rooms.copy()

# Setup the amount cleaned by each person -- which is 0 to start
amount_cleaned_by_person = {}
for person in people:
    amount_cleaned_by_person[person] = 0

while len(rooms_to_clean) > 0:
    
    # Randomly assign a person to a chore
    person = choice(people) 
    room = choice(rooms_to_clean)
    
    # Need to make sure we only add rooms to the list of rooms
    # if the person has already been given at least one room
    if person in people_with_rooms:
        people_with_rooms[person].append(room)
    else:
        people_with_rooms[person] = [room]
    
    # Add the amount cleaned by the person to the list
    amount_cleaned_by_person[person] += rooms_with_size[room]
    
    # This ensures we stop our loop at some point
    rooms_to_clean.remove(room)

# Ensure everyone has something to clean, even if it's no rooms at all
for person in people:
    if person not in people_with_rooms:
        people_with_rooms[person] = []


# See that the amount cleaned by each person is still show here
pprint(amount_cleaned_by_person)


{'adult_one': 800, 'adult_two': 1350, 'kid_one': 450, 'kid_two': 775}

Further analysis on who did what cleaning


In [125]:
from statistics import mean

cleaned = {'adult_one': 700, 'adult_two': 1350, 'kid_one': 600, 'kid_two': 725}

rooms = [
    'kitchen', 'living_room', 'dining_room', 'bedroom_one',
    'bedroom_two', 'master_bedroom', 'bedroom_three', 'basement',
    'attic'
]

values = cleaned.values()

average = mean(values)
maximum = max(values)
minimum = min(values)

max_persons = []
min_persons = []
for person, value in cleaned.items():
    if value == maximum:
        max_persons.append(person)
    
    if value == minimum:
        min_persons.append(person)

print('Average amount cleaned per person:', average)
print('Maximum amount cleaned:', maximum, max_persons)
print('Minimum amount cleaned:', minimum, min_persons)


Average amount cleaned per person: 843.75
Maximum amount cleaned: 1350 ['adult_two']
Minimum amount cleaned: 600 ['kid_one']

In [132]:
## Studio:

text = input("Please enter some text.  ")       # USER INPUT

characters = "ABCDEFGHIJKLMOPQURSTUVWXYZabcdefghijklmnopqrstuvwxyz,.!? "

count = {}                                      # initialize the dictionary

for char in text:
    if char in characters:
        if char in count:
            count[char] = count[char] + 1       # add to the dictionary
        else:
            count[char] = 1                     # build the dictionary

s = sorted(count.keys())                        # sort the return
for key in s:
    print(key, count[key])
    
print(count.keys())


Please enter some text.  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc accumsan sem ut ligula scelerisque sollicitudin. Ut at sagittis augue. Praesent quis rhoncus justo. Aliquam erat volutpat. Donec sit amet suscipit metus, non lobortis massa. Vestibulum augue ex, dapibus ac suscipit vel, volutpat eget massa. Donec nec velit non ligula efficitur luctus
  50
, 4
. 7
A 1
D 2
L 1
P 1
U 1
V 1
a 22
b 3
c 17
d 4
e 26
f 2
g 7
h 1
i 27
j 1
l 17
m 11
n 14
o 15
p 7
q 3
r 9
s 29
t 29
u 28
v 4
x 1
dict_keys(['a', 'x', 's', '.', 'A', 'e', 'h', 'b', 'L', ' ', 'v', 'p', 'i', 't', 'u', 'q', 'm', 'V', 'o', 'n', 'D', 'l', 'd', 'U', 'r', 'P', ',', 'g', 'c', 'j', 'f'])

In [ ]:


In [ ]:
https://lc101-advent.herokuapp.com/